
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>精美桌球游戏</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Segoe UI', sans-serif;
    }

    body {
      background: linear-gradient(135deg, #1a1a1a, #333);
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 20px;
      transition: background 0.3s ease;
    }

    #game-container {
      position: relative;
      background: #084228;
      border-radius: 22px;
      padding: 22px;
      box-shadow: 0 0 44px rgba(0, 0, 0, 0.7), 
                  inset 0 0 22px rgba(0, 0, 0, 0.3);
      max-width: 926px;
      width: 100%;
      margin-top: 44px;
      animation: fadeIn 0.5s ease-out;
    }
    canvas { 
      border-radius: 12px;
      box-shadow: 0 0 32px rgba(0, 0, 0, 0.6),
                  inset 0 0 16px rgba(0, 0, 0, 0.2);
      background: linear-gradient(180deg, #0b6c40, #063822);
      margin-bottom: 44px;
    }

    #game-info {
      position: absolute;
      top: -70px;
      width: calc(100% - 44px);
      display: flex;
      justify-content: space-between;
      align-items: center;
      background: rgba(34, 34, 34, 0.9);
      padding: 14px 22px;
      border-radius: 30px;
      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
    }

    #instructions {
      font-size: 18px;
      color: #ffd700;
      font-style: italic;
      text-shadow: 0 0 8px #ffd700;
    }

    #scoreboard, #timer {
      font-size: 20px;
      color: #fff;
      font-weight: 500;
      display: flex;
      align-items: center;
      gap: 8px;
    }

    #scoreboard span, #timer span {
      color: #48d1cc;
      font-size: 24px;
      font-weight: 700;
    }

    #power-meter {
      position: absolute;
      bottom: -50px;
      left: 50%;
      transform: translateX(-50%);
      width: 80%;
      max-width: 400px;
      height: 10px;
      background: #1a1a1a;
      border-radius: 50px;
      box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
    }

    #power-level {
      height: 100%;
      background: linear-gradient(90deg, #0f0, #ff0, #f00);
      border-radius: 40px;
      transition: width 0.1s linear;
      box-shadow: 0 0 12px rgba(0, 255, 0, 0.3),
                  0 0 12px rgba(255, 255, 0, 0.3),
                  0 0 12px rgba(255, 0, 0, 0.3);
    }

    .tooltip {
      position: absolute;
      background: rgba(34, 34, 34, 0.9);
      color: #fff;
      padding: 6px 12px;
      border-radius: 20px;
      font-size: 14px;
      opacity: 0;
      transition: opacity 0.3s ease;
      pointer-events: none;
    }

    #player-turn {
      position: absolute;
      bottom: -90px;
      left: 50%;
      transform: translateX(-50%);
      color: white;
      font-size: 18px;
      background: rgba(34, 34, 34, 0.9);
      padding: 8px 16px;
      border-radius: 20px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
    }

    .player-indicator {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      margin-right: 8px;
    }

    .solid-color { background-color: #FFD700; }
    .striped-color { background-color: #0000FF; }
  </style>
</head>
<body>
  <div id="game-container">
    <div id="game-info">
      <div id="instructions">
        按住鼠标左键蓄力，松开击球<br>
        方向由鼠标位置决定
      </div>
      <div id="scoreboard">得分：<span id="score">0</span></div>
      <div id="timer">用时：<span id="time">0:00</span></div>
    </div>
    <canvas id="pool-table" width="880" height="440"></canvas>
    <div id="power-meter">
      <div id="power-level"></div>
    </div>
    <div class="tooltip" id="power-tooltip">蓄力强度：<span>0%</span></div>
    <div id="player-turn">
      当前玩家：<span class="player-indicator solid-color"></span>全色球
    </div>
  </div>

  <script>
    // 游戏常量（关键参数放大10%）
    var FRICTION = 0.98;
    var MIN_VELOCITY = 0.1;
    var BALL_RADIUS = 16.5; // 原15px ×1.1
    var POCKET_RADIUS = 23.1; // 原21px ×1.1

    // 获取Canvas和上下文
    var canvas = document.getElementById('pool-table');
    var ctx = canvas.getContext('2d');
    var powerLevel = document.getElementById('power-level');
    var scoreDisplay = document.getElementById('score');
    var timeDisplay = document.getElementById('time');
    var playerTurn = document.getElementById('player-turn');

    // 鼠标位置变量
    var mouseX = 0;
    var mouseY = 0;
    var isMouseInCanvas = false;

    // 游戏状态
    var balls = [];
    var pockets = [];
    var cueBall = null;
    var isCharging = false;
    var chargePower = 0;
    var lastTime = 0;
    var gameRunning = false;
    var whiteBallInPocket = false;
    var score = 0;
    var startTime = 0;
    var isTimerRunning = false;
    var blackBallScoreCondition = false;
    var currentPlayer = 'solid'; // 'solid' 或 'striped'
    var playerAssigned = false;
    var gameStarted = false;

    // 球袋位置
    function createPockets() {
      var offset = 10; // 原20px ×1.1
      return [
        { x: offset, y: offset },
        { x: canvas.width / 2, y: offset-10 },
        { x: canvas.width - offset, y: offset},
        { x: offset, y: canvas.height - offset },
        { x: canvas.width / 2, y: canvas.height - offset+10 },
        { x: canvas.width - offset, y: canvas.height - offset }
      ];
    }

    // 球类定义
    function Ball(x, y, color, number, isCue, ballType) {
      this.x = x;
      this.y = y;
      this.radius = BALL_RADIUS;
      this.color = color;
      this.number = number;
      this.vx = 0;
      this.vy = 0;
      this.isCue = isCue || false;
      this.inPocket = false;
      this.ballType = ballType || null; // 'solid', 'striped', 'black'
    }

    Ball.prototype.draw = function() {
  if (this.inPocket) return;

  // 绘制球体基础
  ctx.beginPath();
  ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
  ctx.fillStyle = this.color;
  ctx.fill();

  // 绘制球的边框
  ctx.beginPath();
  ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
  ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
  ctx.lineWidth = 1.5;
  ctx.stroke();

  // 如果是花色球，绘制上下白色部分
  if (this.ballType === 'striped' && !this.isCue) {
    ctx.save();
    
    // 绘制上白色部分
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius * 0.9, -Math.PI/2, Math.PI/2);
    ctx.fillStyle = 'white';
    ctx.fill();
    
    // 绘制下白色部分
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius * 0.9, Math.PI/2, -Math.PI/2);
    ctx.fillStyle = 'white';
    ctx.fill();
    
    // 绘制中间彩色部分
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius * 0.9, 0, Math.PI * 2);
    ctx.clip();
    ctx.fillStyle = this.color;
    ctx.fillRect(this.x - this.radius, this.y - this.radius * 0.3, 
                this.radius * 2, this.radius * 0.6);
    
    ctx.restore();
  }

  // 绘制球上的数字（不包括白球）
  if (!this.isCue) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius * 0.5, 0, Math.PI * 2);
    ctx.fillStyle = 'white';
    ctx.fill();

    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius * 0.5, 0, Math.PI * 2);
    ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
    ctx.lineWidth = 1;
    ctx.stroke();

    ctx.font = 'bold ' + (this.radius * 0.7) + 'px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillStyle = 'black';
    ctx.fillText(this.number.toString(), this.x, this.y);
  }
};
    // 辅助函数：调整颜色亮度
    function lightenColor(color, percent) {
      var num = parseInt(color.replace("#", ""), 16);
      var amt = Math.round(2.55 * percent);
      var R = (num >> 16) + amt;
      var G = ((num >> 8) & 0x00FF) + amt;
      var B = (num & 0x0000FF) + amt;
      
      return "#" + (
        0x1000000 + 
        (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + 
        (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + 
        (B < 255 ? B < 1 ? 0 : B : 255)
      ).toString(16).slice(1);
    }

    Ball.prototype.update = function() {
      if (this.inPocket) return;
      
      // 应用摩擦力
      this.vx *= FRICTION;
      this.vy *= FRICTION;
      
      // 当速度足够小时停止
      if (Math.abs(this.vx) < MIN_VELOCITY && Math.abs(this.vy) < MIN_VELOCITY) {
        this.vx = 0;
        this.vy = 0;
      }
      
      // 更新位置
      this.x += this.vx;
      this.y += this.vy;

      // 边界检测和反弹
      if (this.x - this.radius < 0) {
        this.x = this.radius;
        this.vx = -this.vx * 0.9; // 能量损失
      } else if (this.x + this.radius > canvas.width) {
        this.x = canvas.width - this.radius;
        this.vx = -this.vx * 0.9;
      }

      if (this.y - this.radius < 0) {
        this.y = this.radius;
        this.vy = -this.vy * 0.9;
      } else if (this.y + this.radius > canvas.height) {
        this.y = canvas.height - this.radius;
        this.vy = -this.vy * 0.9;
      }

      // 检测是否落袋
      for (var i = 0; i < pockets.length; i++) {
        var pocket = pockets[i];
        var dx = this.x - pocket.x;
        var dy = this.y - pocket.y;
        var distance = Math.sqrt(dx * dx + dy * dy);
        
        if (distance < POCKET_RADIUS && !this.inPocket) {
          this.inPocket = true;
          
          if (!this.isCue) {
            if (this.number === 8) {
              if (blackBallScoreCondition) {
                score++;
                scoreDisplay.textContent = score;
                setTimeout(function() {
                  var endTime = performance.now() / 1000;
                  var elapsedTime = endTime - startTime;
                  alert('黑球进袋！游戏结束！最终得分：' + score + '，用时：' + elapsedTime.toFixed(2) + ' 秒');
                  initGame();
                }, 500);
              } else {
                setTimeout(function() {
                  alert('黑球提前进袋！游戏重新开始！');
                  initGame();
                }, 500);
              }
              return;
            } else {
              score++;
              scoreDisplay.textContent = score;
              
              // 确定玩家类型
              if (!playerAssigned && gameStarted) {
                playerAssigned = true;
                currentPlayer = this.ballType;
                updatePlayerTurn();
              }
              
              // 检查是否打进了正确类型的球
              if (playerAssigned && this.ballType === currentPlayer) {
                // 继续当前玩家回合
              } else if (playerAssigned) {
                // 切换玩家
                currentPlayer = currentPlayer === 'solid' ? 'striped' : 'solid';
                updatePlayerTurn();
              }
              
              // 检查是否所有目标球都已进袋
              if (balls.filter(function(b) { return !b.isCue && !b.inPocket && b.number !== 8; }).length === 0) {
                blackBallScoreCondition = true;
              }
              
              // 检查是否所有球都已进袋
              if (balls.filter(function(b) { return !b.isCue && !b.inPocket; }).length === 0) {
                var endTime = performance.now() / 1000;
                var elapsedTime = endTime - startTime;
                setTimeout(function() {
                  alert('恭喜！游戏胜利！最终得分：' + score + '，用时：' + elapsedTime.toFixed(2) + ' 秒');
                  initGame();
                }, 500);
              }
            }
          } else {
            whiteBallInPocket = true;
            resetCueBall();
            // 白球落袋，切换玩家
            if (playerAssigned) {
              currentPlayer = currentPlayer === 'solid' ? 'striped' : 'solid';
              updatePlayerTurn();
            }
          }
        }
      }
    };

    // 更新玩家回合显示
      function updatePlayerTurn() {
    var playerTurnElement = document.getElementById('player-turn');
    if (!playerTurnElement) return;
    var indicator = playerTurnElement.querySelector('.player-indicator');
    var textElement = playerTurnElement.querySelector('span:not(.player-indicator)');
    if (textElement) {
        if (currentPlayer === 'solid') {
            indicator.className = 'player-indicator solid-color';
            textElement.textContent = '全色球';
        } else {
            indicator.className = 'player-indicator striped-color';
            textElement.textContent = '花色球';
        }
    }
}
    // 初始化游戏
    function initGame() {
      score = 0;
      scoreDisplay.textContent = score;
      timeDisplay.textContent = '0:00';
      balls = [];
      pockets = createPockets();
      whiteBallInPocket = false;
      cueBall = new Ball(canvas.width / 4, canvas.height / 2, 'white', 0, true);
      balls.push(cueBall);
      
      // 定义球的类型和颜色
      var ballTypes = [
        { type: 'solid', color: '#FFD700' },    // 1
        { type: 'solid', color: '#FF0000' },    // 2
        { type: 'solid', color: '#0000FF' },    // 3
        { type: 'solid', color: '#800080' },    // 4
        { type: 'solid', color: '#FFA500' },    // 5
        { type: 'solid', color: '#008000' },    // 6
        { type: 'solid', color: '#800000' },    // 7
        { type: 'black', color: '#000000' },    // 8
        { type: 'striped', color: '#FFD700' },  // 9
        { type: 'striped', color: '#FF0000' },  // 10
        { type: 'striped', color: '#0000FF' },  // 11
        { type: 'striped', color: '#800080' },  // 12
        { type: 'striped', color: '#FFA500' },  // 13
        { type: 'striped', color: '#008000' },  // 14
        { type: 'striped', color: '#800000' }   // 15
      ];
      
      // 三角形排列的球
      var startX = canvas.width * 4.8/7;
      var startY = canvas.height / 2;
      var row = 0;
      var count = 0;
      
      for (var i = 1; i <= 5; i++) {
        for (var j = 0; j < i; j++) {
          var x = startX + row * BALL_RADIUS * 1.8;
          var y = startY - (i - 1) * BALL_RADIUS * 1.8 / 2 + j * BALL_RADIUS * 1.8;
          balls.push(new Ball(x, y, ballTypes[count].color, count + 1, false, ballTypes[count].type));
          count++;
        }
        row++;
      }
      
      gameRunning = true;
      blackBallScoreCondition = false;
      isTimerRunning = false;
      startTime = 0;
      lastTime = 0;
      
      // 重置玩家状态
      currentPlayer = 'solid';
    playerAssigned = false;
    gameStarted = false;
    document.addEventListener('DOMContentLoaded', function () {
        updatePlayerTurn();
        requestAnimationFrame(gameLoop);
    });
    }

    // 重置白球位置
    function resetCueBall() {
      cueBall.x = canvas.width / 4;
      cueBall.y = canvas.height / 2;
      cueBall.vx = 0;
      cueBall.vy = 0;
      cueBall.inPocket = false;
      whiteBallInPocket = false;
    }

    // 碰撞检测
    function checkCollisions() {
      for (var i = 0; i < balls.length; i++) {
        for (var j = i + 1; j < balls.length; j++) {
          var ball1 = balls[i];
          var ball2 = balls[j];
          
          // 跳过已落袋的球
          if (ball1.inPocket || ball2.inPocket) continue;
          
          // 计算两球之间的距离
          var dx = ball2.x - ball1.x;
          var dy = ball2.y - ball1.y;
          var distance = Math.sqrt(dx * dx + dy * dy);
          
          // 如果两球相撞
          if (distance < ball1.radius + ball2.radius) {
            // 计算碰撞角度
            var angle = Math.atan2(dy, dx);
            var sin = Math.sin(angle);
            var cos = Math.cos(angle);
            
            // 转换到碰撞坐标系
            var x1 = 0;
            var y1 = 0;
            var x2 = dx * cos + dy * sin;
            var y2 = dy * cos - dx * sin;
            
            // 转换速度到碰撞坐标系
            var vx1 = ball1.vx * cos + ball1.vy * sin;
            var vy1 = ball1.vy * cos - ball1.vx * sin;
            var vx2 = ball2.vx * cos + ball2.vy * sin;
            var vy2 = ball2.vy * cos - ball2.vx * sin;
            
            // 计算碰撞后的速度 (一维弹性碰撞公式)
            var vx1Final = ((ball1.radius - ball2.radius) * vx1 + 2 * ball2.radius * vx2) / (ball1.radius + ball2.radius);
            var vx2Final = ((ball2.radius - ball1.radius) * vx2 + 2 * ball1.radius * vx1) / (ball1.radius + ball2.radius);
            
            // 分离重叠的球
            var overlap = (ball1.radius + ball2.radius) - distance;
            ball1.x -= overlap * cos / 2;
            ball1.y -= overlap * sin / 2;
            ball2.x += overlap * cos / 2;
            ball2.y += overlap * sin / 2;
            
            // 转换回原坐标系
            ball1.vx = vx1Final * cos - vy1 * sin;
            ball1.vy = vy1 * cos + vx1Final * sin;
            ball2.vx = vx2Final * cos - vy2 * sin;
            ball2.vy = vy2 * cos + vx2Final * sin;
          }
        }
      }
    }

    // 绘制真实台球杆
    function drawCue() {
      if (cueBall.inPocket || !isMouseInCanvas) return;
      
      var angle = Math.atan2(mouseY - cueBall.y, mouseX - cueBall.x);
      var cueLength = 250; // 更长的球杆，更真实
      var startX = cueBall.x + Math.cos(angle) * (cueBall.radius + 3); // 更贴近球
      var startY = cueBall.y + Math.sin(angle) * (cueBall.radius + 3);
      var endX = startX + Math.cos(angle) * cueLength;
      var endY = startY + Math.sin(angle) * cueLength;
      
      // 绘制球杆
      ctx.save();
      ctx.translate(startX, startY);
      ctx.rotate(angle);
      
      // 球杆参数
      var tipRadius = 3; // 杆头半径
      var tipLength = 14; // 杆头长度
      var ferruleLength = 5; // 金属箍长度
      var shaftMaxWidth = 8; // 杆身最大宽度
      var gripWidth = 14; // 握把宽度
      var gripLength = cueLength * 0.3; // 握把长度
      
      // 绘制杆头 (皮革部分)
      ctx.beginPath();
      ctx.moveTo(0, -tipRadius);
      ctx.lineTo(tipLength, -tipRadius * 0.7);
      ctx.lineTo(tipLength, tipRadius * 0.7);
      ctx.lineTo(0, tipRadius);
      ctx.closePath();
      ctx.fillStyle = '#8B4513'; // 棕色皮革
      ctx.fill();
      
      // 绘制金属箍
      ctx.beginPath();
      ctx.moveTo(tipLength, -tipRadius * 0.7);
      ctx.lineTo(tipLength + ferruleLength, -shaftMaxWidth/2);
      ctx.lineTo(tipLength + ferruleLength, shaftMaxWidth/2);
      ctx.lineTo(tipLength, tipRadius * 0.7);
      ctx.closePath();
      ctx.fillStyle = '#C0C0C0'; // 银色
      ctx.fill();
      
      // 绘制杆身
      ctx.beginPath();
      ctx.moveTo(tipLength + ferruleLength, -shaftMaxWidth/2);
      ctx.lineTo(cueLength - gripLength, -shaftMaxWidth/2);
      ctx.lineTo(cueLength, -gripWidth/2);
      ctx.lineTo(cueLength, gripWidth/2);
      ctx.lineTo(cueLength - gripLength, shaftMaxWidth/2);
      ctx.lineTo(tipLength + ferruleLength, shaftMaxWidth/2);
      ctx.closePath();
      
      // 创建杆身渐变 (木质纹理)
      var shaftGradient = ctx.createLinearGradient(0, 0, cueLength, 0);
      shaftGradient.addColorStop(0, '#DEB887'); // 浅棕色
      shaftGradient.addColorStop(0.5, '#CD853F'); // 棕色
      shaftGradient.addColorStop(1, '#8B4513'); // 深棕色
      
      ctx.fillStyle = shaftGradient;
      ctx.fill();
      
      // 添加杆身纹理
      for (var i = tipLength + ferruleLength; i < cueLength - gripLength; i += 8) {
        ctx.beginPath();
        ctx.moveTo(i, -shaftMaxWidth/2 - 1);
        ctx.lineTo(i, shaftMaxWidth/2 + 1);
        ctx.lineWidth = 0.5;
        ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
        ctx.stroke();
      }
      
      // 绘制握把
      ctx.beginPath();
      ctx.moveTo(cueLength - gripLength, -shaftMaxWidth/2);
      ctx.lineTo(cueLength, -gripWidth/2);
      ctx.lineTo(cueLength, gripWidth/2);
      ctx.lineTo(cueLength - gripLength, shaftMaxWidth/2);
      ctx.closePath();
      
      // 创建握把渐变 (黑色皮革)
      var gripGradient = ctx.createLinearGradient(cueLength - gripLength, 0, cueLength, 0);
      gripGradient.addColorStop(0, '#333333');
      gripGradient.addColorStop(1, '#000000');
      
      ctx.fillStyle = gripGradient;
      ctx.fill();
      
      // 添加握把纹理
      for (var i = cueLength - gripLength; i < cueLength; i += 5) {
        ctx.beginPath();
        ctx.moveTo(i, -gripWidth/2);
        ctx.lineTo(i, gripWidth/2);
        ctx.lineWidth = 0.5;
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
        ctx.stroke();
      }
      
      // 绘制握把末端装饰
      ctx.beginPath();
      ctx.arc(cueLength, 0, gripWidth/2, 0, Math.PI * 2);
      ctx.fillStyle = '#C0C0C0'; // 银色
      ctx.fill();
      
      // 绘制蓄力指示器
      if (isCharging) {
        var powerOffset = 15; // 蓄力指示器与球杆的偏移
        var powerBarLength = 60;
        var powerBarWidth = 6;
        
        // 绘制蓄力条背景
        ctx.beginPath();
        ctx.rect(cueLength - powerBarLength, -shaftMaxWidth/2 - powerOffset - powerBarWidth/2, powerBarLength, powerBarWidth);
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fill();
        
        // 绘制蓄力条
        var powerProgress = powerBarLength * (chargePower / 100);
        var powerGradient = ctx.createLinearGradient(cueLength - powerBarLength, 0, cueLength, 0);
        powerGradient.addColorStop(0, 'rgba(255, 0, 0, 0.8)');
        powerGradient.addColorStop(0.5, 'rgba(255, 255, 0, 0.8)');
        powerGradient.addColorStop(1, 'rgba(0, 255, 0, 0.8)');
        
        ctx.beginPath();
        ctx.rect(cueLength - powerBarLength, -shaftMaxWidth/2 - powerOffset - powerBarWidth/2, powerProgress, powerBarWidth);
        ctx.fillStyle = powerGradient;
        ctx.fill();
        
        // 绘制蓄力百分比文本
        ctx.fillStyle = 'white';
        ctx.font = '10px Arial';
        ctx.textAlign = 'right';
        ctx.textBaseline = 'middle';
        ctx.fillText(Math.round(chargePower) + '%', cueLength, -shaftMaxWidth/2 - powerOffset - powerBarWidth/2 - 8);
      }
      
      ctx.restore();
    }
    
    // 绘制桌球台
    function drawTable() {
      ctx.fillStyle = '#0a5c36';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      
      // 绘制边框
      ctx.strokeStyle = '#654321';
      ctx.lineWidth = 22; // 原20px ×1.1
      ctx.strokeRect(0, 0, canvas.width, canvas.height);
      
      // 绘制球袋
      ctx.fillStyle = 'black';
      for (var i = 0; i < pockets.length; i++) {
        var pocket = pockets[i];
        ctx.beginPath();
        ctx.arc(pocket.x, pocket.y, POCKET_RADIUS, 0, Math.PI * 2);
        ctx.fill();
      }
      
      // 绘制中间线
      ctx.strokeStyle = 'white';
      ctx.lineWidth = 1.1; // 原1px ×1.1
      ctx.setLineDash([5.5, 5.5]); // 原5px ×1.1
      ctx.beginPath();
      ctx.moveTo(canvas.width / 4, 0);
      ctx.lineTo(canvas.width / 4, canvas.height);
      ctx.stroke();
      ctx.setLineDash([]);
      
      // 绘制中间点
      ctx.beginPath();
      ctx.arc(canvas.width / 4, canvas.height / 2, 3.3, 0, Math.PI * 2); // 原3px ×1.1
      ctx.fillStyle = 'white';
      ctx.fill();
      
      // 绘制球型号码位置标记
      ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
      var markerRadius = 2;
      var startX = canvas.width * 4.8/7;
      var startY = canvas.height / 2;
      var row = 0;
      
      for (var i = 1; i <= 5; i++) {
        for (var j = 0; j < i; j++) {
          var x = startX + row * BALL_RADIUS * 1.8;
          var y = startY - (i - 1) * BALL_RADIUS * 1.8 / 2 + j * BALL_RADIUS * 1.8;
          ctx.beginPath();
          ctx.arc(x, y, markerRadius, 0, Math.PI * 2);
          ctx.fill();
        }
        row++;
      }
    }

    // 辅助函数
    function allBallsStopped() {
      for (var i = 0; i < balls.length; i++) {
        var ball = balls[i];
        if (!ball.inPocket && (Math.abs(ball.vx) > MIN_VELOCITY || Math.abs(ball.vy) > MIN_VELOCITY)) {
          return false;
        }
      }
      return true;
    }

    // 主循环
    function gameLoop(timestamp) {
      if (!gameRunning) return;
      
      var deltaTime = timestamp - lastTime;
      lastTime = timestamp;
      
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      drawTable();
      
      for (var i = 0; i < balls.length; i++) {
        balls[i].update();
      }
      
      checkCollisions();
      
      for (var i = 0; i < balls.length; i++) {
        balls[i].draw();
      }
      
      if (allBallsStopped() && !whiteBallInPocket) {
        drawCue();
        // 游戏开始标记
        if (!gameStarted) {
          gameStarted = true;
        }
      }
      
      // 更新蓄力条
      if (isCharging) {
        chargePower = Math.min(chargePower + deltaTime / 30, 100);
        powerLevel.style.width = chargePower + '%';
        
        // 更新蓄力提示
        var tooltip = document.getElementById('power-tooltip');
        tooltip.querySelector('span').textContent = Math.round(chargePower) + '%';
        tooltip.style.opacity = '1';
        tooltip.style.left = (mouseX + 20) + 'px';
        tooltip.style.top = (mouseY - 30) + 'px';
      } else {
        document.getElementById('power-tooltip').style.opacity = '0';
      }
      
      // 启动计时器
      if (gameRunning && !isTimerRunning) {
        startTime = performance.now() / 1000;
        isTimerRunning = true;
      }
      
      // 更新计时器显示
      if (isTimerRunning) {
        var currentTime = performance.now() / 1000 - startTime;
        var minutes = Math.floor(currentTime / 60);
        var seconds = Math.floor(currentTime % 60);
        var formattedTime = (minutes < 10? '0' : '') + minutes + ':' + (seconds < 10? '0' : '') + seconds;
        timeDisplay.textContent = formattedTime;
      }
      
      requestAnimationFrame(gameLoop);
    }

    // 鼠标事件
    canvas.addEventListener('mousedown', function(e) {
      if (allBallsStopped() && !whiteBallInPocket && isMouseInCanvas) {
        isCharging = true;
        chargePower = 0;
      }
    });

    canvas.addEventListener('mouseup', function(e) {
      if (isCharging) {
        isCharging = false;
        
        var rect = canvas.getBoundingClientRect();
        mouseX = e.clientX - rect.left;
        mouseY = e.clientY - rect.top;
        
        var angle = Math.atan2(mouseY - cueBall.y, mouseX - cueBall.x);
        var power = chargePower / 4;
        
        // 设置白球速度
        cueBall.vx = -Math.cos(angle) * power;
        cueBall.vy = -Math.sin(angle) * power;
        
        // 重置蓄力条
        powerLevel.style.width = '0%';
      }
    });

    canvas.addEventListener('mousemove', function(e) {
      var rect = canvas.getBoundingClientRect();
      mouseX = e.clientX - rect.left;
      mouseY = e.clientY - rect.top;
      
      isMouseInCanvas = 
        mouseX >= 0 && mouseX <= canvas.width && 
        mouseY >= 0 && mouseY <= canvas.height;
    });

    canvas.addEventListener('mouseleave', function() {
      isMouseInCanvas = false;
      document.getElementById('power-tooltip').style.opacity = '0';
    });

    canvas.addEventListener('mouseenter', function() {
      isMouseInCanvas = true;
    });

    // 开始游戏
    initGame();
  </script>
<!-- Code injected by live-server -->
<script>
	// <![CDATA[  <-- For SVG support
	if ('WebSocket' in window) {
		(function () {
			function refreshCSS() {
				var sheets = [].slice.call(document.getElementsByTagName("link"));
				var head = document.getElementsByTagName("head")[0];
				for (var i = 0; i < sheets.length; ++i) {
					var elem = sheets[i];
					var parent = elem.parentElement || head;
					parent.removeChild(elem);
					var rel = elem.rel;
					if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
						var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
						elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
					}
					parent.appendChild(elem);
				}
			}
			var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
			var address = protocol + window.location.host + window.location.pathname + '/ws';
			var socket = new WebSocket(address);
			socket.onmessage = function (msg) {
				if (msg.data == 'reload') window.location.reload();
				else if (msg.data == 'refreshcss') refreshCSS();
			};
			if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
				console.log('Live reload enabled.');
				sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
			}
		})();
	}
	else {
		console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
	}
	// ]]>
</script>
</body>
</html>    